home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / C++ / Direct3D / MultiAnimation / Tiny.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-27  |  36.4 KB  |  1,168 lines

  1. //-----------------------------------------------------------------------------
  2. // File: Tiny.cpp
  3. //
  4. // Desc: Defines the character class, CTiny, for the MultipleAnimation sample.
  5. //       The class does some basic things to make the character aware of
  6. //       its surroundings, as well as implements all actions and movements.
  7. //       CTiny shows a full-featured example of this.  These
  8. //       classes use the MultiAnimation class library to control the
  9. //       animations.
  10. //
  11. // Copyright (c) Microsoft Corporation. All rights reserved
  12. //-----------------------------------------------------------------------------
  13.  
  14. #include "dxstdafx.h"
  15. #include "MultiAnimation.h"
  16. #include "DXUTsound.h"
  17. #include "Tiny.h"
  18.  
  19. using namespace std;
  20.  
  21.  
  22. CSound *g_apSoundsTiny[ 2 ];
  23.  
  24.  
  25.  
  26.  
  27. //-----------------------------------------------------------------------------
  28. // Name: CTiny::CTiny
  29. // Desc: Constructor for CTiny
  30. //-----------------------------------------------------------------------------
  31. CTiny::CTiny() :
  32.     m_pMA( NULL ),
  33.     m_dwMultiAnimIdx( 0 ),
  34.     m_pAI( NULL ),
  35.     m_pv_pChars( NULL ),
  36.     m_pSM( NULL ),
  37.  
  38.     m_dTimePrev( 0.0 ),
  39.     m_dTimeCurrent( 0.0 ),
  40.     m_bUserControl( false ),
  41.     m_bPlaySounds( true ),
  42.     m_dwCurrentTrack( 0 ),
  43.  
  44.     m_fSpeed( 0.f ),
  45.     m_fSpeedTurn( 0.f ),
  46.     m_pCallbackHandler( NULL ),
  47.     m_fPersonalRadius( 0.f ),
  48.  
  49.     m_fSpeedWalk( 1.f / 5.7f ),
  50.     m_fSpeedJog( 1.f / 2.3f ),
  51.  
  52.     m_bIdle( false ),
  53.     m_bWaiting( false ),
  54.     m_dTimeIdling( 0.0 ),
  55.     m_dTimeWaiting( 0.0 ),
  56.     m_dTimeBlocked( 0.0 )
  57. {
  58.     D3DXMatrixIdentity( &m_mxOrientation );
  59.  
  60.     m_fSpeedTurn = 1.3f;
  61.     m_pCallbackHandler = NULL;
  62.     m_fPersonalRadius = .035f;
  63.  
  64.     m_szASName[0] = '\0';
  65. }
  66.  
  67.  
  68.  
  69.  
  70. //-----------------------------------------------------------------------------
  71. // Name: CTiny::~CTiny
  72. // Desc: Destructor for CTiny
  73. //-----------------------------------------------------------------------------
  74. CTiny::~CTiny()
  75. {
  76.     Cleanup();
  77. }
  78.  
  79.  
  80.  
  81.  
  82. //-----------------------------------------------------------------------------
  83. // Name: CTiny::Setup
  84. // Desc: Initializes the class and readies it for animation
  85. //-----------------------------------------------------------------------------
  86. HRESULT CTiny::Setup( CMultiAnim *pMA,
  87.                            vector< CTiny* > *pv_pChars,
  88.                            CSoundManager *pSM,
  89.                            double dTimeCurrent )
  90. {
  91.     m_pMA = pMA;
  92.     m_pv_pChars = pv_pChars;
  93.     m_pSM = pSM;
  94.  
  95.     m_dTimeCurrent = m_dTimePrev = dTimeCurrent;
  96.  
  97.     HRESULT hr;
  98.     hr = m_pMA->CreateNewInstance( & m_dwMultiAnimIdx );
  99.     if( FAILED( hr ) )
  100.         return E_OUTOFMEMORY;
  101.  
  102.     m_pAI = m_pMA->GetInstance( m_dwMultiAnimIdx );
  103.  
  104.     // set initial position
  105.     bool bBlocked = true;
  106.     DWORD dwAttempts;
  107.     for( dwAttempts = 0; dwAttempts < 1000 && bBlocked; ++ dwAttempts )
  108.     {
  109.         ChooseNewLocation( & m_vPos );
  110.         bBlocked = IsBlockedByCharacter( & m_vPos );
  111.     }
  112.  
  113.     m_fFacing = 0.0f;
  114.  
  115.     // set up anim indices
  116.     m_dwAnimIdxLoiter = GetAnimIndex( "Loiter" );
  117.     m_dwAnimIdxWalk = GetAnimIndex( "Walk" );
  118.     m_dwAnimIdxJog = GetAnimIndex( "Jog" );
  119.     if( m_dwAnimIdxLoiter == ANIMINDEX_FAIL ||
  120.         m_dwAnimIdxWalk == ANIMINDEX_FAIL ||
  121.         m_dwAnimIdxJog == ANIMINDEX_FAIL )
  122.         return E_FAIL;
  123.  
  124.     // set up callback key data
  125.     m_CallbackData[ 0 ].m_dwFoot = 0;
  126.     m_CallbackData[ 0 ].m_pvTinyPos = & m_vPos;
  127.     m_CallbackData[ 1 ].m_dwFoot = 1;
  128.     m_CallbackData[ 1 ].m_pvTinyPos = & m_vPos;
  129.  
  130.     // set up footstep callbacks
  131.     SetupCallbacksAndCompression();
  132.     m_pCallbackHandler = new CBHandlerTiny;
  133.     if( m_pCallbackHandler == NULL )
  134.         return E_OUTOFMEMORY;
  135.  
  136.     // set up footstep sounds
  137.     WCHAR sPath[ MAX_PATH ];
  138.     if( g_apSoundsTiny[ 0 ] == NULL )
  139.     {
  140.         hr = DXUTFindDXSDKMediaFileCch( sPath, MAX_PATH, FOOTFALLSOUND00 );
  141.         if( FAILED( hr ) )
  142.             wcsncpy( sPath, FOOTFALLSOUND00, MAX_PATH );
  143.  
  144.         hr = m_pSM->Create( & g_apSoundsTiny[ 0 ], sPath, DSBCAPS_CTRLVOLUME );
  145.         if( FAILED( hr ) )
  146.         {
  147.             OutputDebugString( FOOTFALLSOUND00 L" not found; continuing without sound.\n" );
  148.             m_bPlaySounds = false;
  149.         }
  150.     }
  151.  
  152.     if( g_apSoundsTiny[ 1 ] == NULL )
  153.     {
  154.         hr = DXUTFindDXSDKMediaFileCch( sPath, MAX_PATH, FOOTFALLSOUND01 );
  155.         if( FAILED( hr ) )
  156.             wcsncpy( sPath, FOOTFALLSOUND01, MAX_PATH );
  157.  
  158.         hr = m_pSM->Create( & g_apSoundsTiny[ 1 ], sPath, DSBCAPS_CTRLVOLUME );
  159.         if( FAILED( hr ) )
  160.         {
  161.             OutputDebugString( FOOTFALLSOUND01 L" not found; continuing without sound.\n" );
  162.             m_bPlaySounds = false;
  163.         }
  164.     }
  165.  
  166.     // compute reorientation matrix based on default orientation and bounding radius
  167.     D3DXMATRIX mx;
  168.     float fScale = 1.f / m_pMA->GetBoundingRadius() / 7.f;
  169.     D3DXMatrixScaling( & mx, fScale, fScale, fScale );
  170.     m_mxOrientation = mx;
  171.     D3DXMatrixRotationX( & mx, -D3DX_PI / 2.0f );
  172.     D3DXMatrixMultiply( & m_mxOrientation, & m_mxOrientation, & mx );
  173.     D3DXMatrixRotationY( & mx, D3DX_PI / 2.0f );
  174.     D3DXMatrixMultiply( & m_mxOrientation, & m_mxOrientation, & mx );
  175.  
  176.     // set starting target
  177.     SetSeekingState();
  178.     ComputeFacingTarget();
  179.  
  180.     LPD3DXANIMATIONCONTROLLER pAC;
  181.     m_pAI->GetAnimController( & pAC );
  182.     pAC->AdvanceTime( m_dTimeCurrent, NULL );
  183.     pAC->Release();
  184.  
  185.     // Add this instance to the list
  186.     try
  187.     {
  188.         pv_pChars->push_back( this );
  189.     }
  190.     catch( ... )
  191.     {
  192.         return E_OUTOFMEMORY;
  193.     }
  194.  
  195.     return S_OK;
  196. }
  197.  
  198.  
  199.  
  200.  
  201. //-----------------------------------------------------------------------------
  202. // Name: CTiny::Cleanup()
  203. // Desc: Performs cleanup tasks for CTiny
  204. //-----------------------------------------------------------------------------
  205. void CTiny::Cleanup()
  206. {
  207.     delete m_pCallbackHandler; m_pCallbackHandler = NULL;
  208. }
  209.  
  210.  
  211.  
  212.  
  213. //-----------------------------------------------------------------------------
  214. // Name: CTiny::GetAnimInstance()
  215. // Desc: Returns the CAnimInstance object that this instance of CTiny
  216. //       embeds.
  217. //-----------------------------------------------------------------------------
  218. CAnimInstance *CTiny::GetAnimInstance()
  219. {
  220.     return m_pAI;
  221. }
  222.  
  223.  
  224.  
  225.  
  226. //-----------------------------------------------------------------------------
  227. // Name: CTiny::GetPosition()
  228. // Desc: Returns the position of this instance.
  229. //-----------------------------------------------------------------------------
  230. void CTiny::GetPosition( D3DXVECTOR3 *pV )
  231. {
  232.     *pV = m_vPos;
  233. }
  234.  
  235.  
  236.  
  237.  
  238. //-----------------------------------------------------------------------------
  239. // Name: CTiny::GetFacing()
  240. // Desc: Returns a unit vector representing the direction this CTiny
  241. //       instance is facing.
  242. //-----------------------------------------------------------------------------
  243. void CTiny::GetFacing( D3DXVECTOR3 *pV )
  244. {
  245.     D3DXMATRIX m;
  246.     *pV = D3DXVECTOR3( 1.0f, 0.0f, 0.0f );
  247.     D3DXVec3TransformCoord( pV, pV, D3DXMatrixRotationY( &m, -m_fFacing ) );
  248. }
  249.  
  250.  
  251.  
  252.  
  253. //-----------------------------------------------------------------------------
  254. // Name: CTiny::Animate()
  255. // Desc: Advances the local time by dTimeDelta. Determine an action for Tiny,
  256. //       then update the animation controller's tracks to reflect the action.
  257. //-----------------------------------------------------------------------------
  258. void CTiny::Animate( double dTimeDelta )
  259. {
  260.     // adjust position and facing based on movement mode
  261.     if( m_bUserControl )
  262.         AnimateUserControl( dTimeDelta );  // user-controlled
  263.     else if( m_bIdle )
  264.         AnimateIdle( dTimeDelta );         // idling - not turning toward
  265.     else
  266.         AnimateMoving( dTimeDelta );       // moving or waiting - turning toward
  267.  
  268.     // loop the loiter animation back on itself to avoid the end-to-end jerk
  269.     SmoothLoiter();
  270.  
  271.     D3DXMATRIX mxWorld, mx;
  272.  
  273.     // compute world matrix based on pos/face
  274.     D3DXMatrixRotationY( & mxWorld, -m_fFacing );
  275.     D3DXMatrixTranslation( & mx, m_vPos.x, m_vPos.y, m_vPos.z );
  276.     D3DXMatrixMultiply( & mxWorld, & mxWorld, & mx );
  277.     D3DXMatrixMultiply( & mxWorld, & m_mxOrientation, & mxWorld );
  278.     m_pAI->SetWorldTransform( & mxWorld );
  279. }
  280.  
  281.  
  282.  
  283.  
  284. //-----------------------------------------------------------------------------
  285. // Name: CTiny::ResetTime()
  286. // Desc: Resets the local time for this CTiny instance.
  287. //-----------------------------------------------------------------------------
  288. HRESULT CTiny::ResetTime()
  289. {
  290.     m_dTimeCurrent = m_dTimePrev = 0.0;
  291.     return m_pAI->ResetTime();
  292. }
  293.  
  294.  
  295.  
  296.  
  297. //-----------------------------------------------------------------------------
  298. // Name: CTiny::AdvanceTime()
  299. // Desc: Advances the local animation time by dTimeDelta, and call
  300. //       CAnimInstance to set up its frames to reflect the time advancement.
  301. //-----------------------------------------------------------------------------
  302. HRESULT CTiny::AdvanceTime( double dTimeDelta, D3DXVECTOR3 *pvEye )
  303. {
  304.     // if we're playing sounds, set the sound source position
  305.     if( m_bPlaySounds )
  306.     {
  307.         m_CallbackData[ 0 ].m_pvCameraPos = pvEye;
  308.         m_CallbackData[ 1 ].m_pvCameraPos = pvEye;
  309.     }
  310.     else    // else, set it to null to let the handler know to be quiet
  311.     {
  312.         m_CallbackData[ 0 ].m_pvCameraPos = NULL;
  313.         m_CallbackData[ 1 ].m_pvCameraPos = NULL;
  314.     }
  315.  
  316.     m_dTimePrev = m_dTimeCurrent;
  317.     m_dTimeCurrent += dTimeDelta;
  318.     return m_pAI->AdvanceTime( dTimeDelta, m_pCallbackHandler );
  319. }
  320.  
  321.  
  322.  
  323.  
  324. //-----------------------------------------------------------------------------
  325. // Name: CTiny::Draw()
  326. // Desc: Renders this CTiny instace using the current animation frames.
  327. //-----------------------------------------------------------------------------
  328. HRESULT CTiny::Draw()
  329. {
  330.     return m_pAI->Draw();
  331. }
  332.  
  333.  
  334.  
  335.  
  336. //-----------------------------------------------------------------------------
  337. // Name: CTiny::Report()
  338. // Desc: Add to the vector of strings, v_sReport, with useful information
  339. //       about this instance of CTiny.
  340. //-----------------------------------------------------------------------------
  341. void CTiny::Report( vector < String > & v_sReport )
  342. {
  343.     WCHAR s[ 256 ];
  344.  
  345.     try
  346.     {
  347.         swprintf( s, L"Pos: %f, %f", m_vPos.x, m_vPos.z );
  348.         v_sReport.push_back( String( s ) );
  349.         swprintf( s, L"Facing: %f", m_fFacing );
  350.         v_sReport.push_back( String( s ) );
  351.         swprintf( s, L"Local time: %f", m_dTimeCurrent );
  352.         v_sReport.push_back( String( s ) );
  353.         swprintf( s, L"Pos Target: %f, %f", m_vPosTarget.x, m_vPosTarget.z );
  354.         v_sReport.push_back( String( s ) );
  355.         swprintf( s, L"Facing Target: %f", m_fFacingTarget );
  356.         v_sReport.push_back( String( s ) );
  357.         swprintf( s, L"Status: %s", m_bIdle ? L"Idle" : ( m_bWaiting ? L"Waiting" : L"Moving" ) );
  358.         v_sReport.push_back( String( s ) );
  359.  
  360.         // report track data
  361.         LPD3DXANIMATIONCONTROLLER pAC;
  362.         LPD3DXANIMATIONSET pAS;
  363.         D3DXTRACK_DESC td;
  364.         m_pAI->GetAnimController( & pAC );
  365.  
  366.         pAC->GetTrackAnimationSet( 0, & pAS );
  367.         WCHAR wstr[256];
  368.         MultiByteToWideChar( CP_ACP, 0, pAS->GetName(), -1, wstr, 256 );
  369.         swprintf( s, L"Track 0: %s%s", wstr, m_dwCurrentTrack == 0 ? L" (current)" : L"" );
  370.         v_sReport.push_back( String( s ) );
  371.         pAS->Release();
  372.  
  373.         pAC->GetTrackDesc( 0, & td );
  374.         swprintf( s, L"  Weight: %f", td.Weight );
  375.         v_sReport.push_back( String( s ) );
  376.         swprintf( s, L"  Speed: %f", td.Speed );
  377.         v_sReport.push_back( String( s ) );
  378.         swprintf( s, L"  Position: %f", td.Position );
  379.         v_sReport.push_back( String( s ) );
  380.         swprintf( s, L"  Enable: %s", td.Enable ? L"true" : L"false" );
  381.         v_sReport.push_back( String( s ) );
  382.  
  383.         pAC->GetTrackAnimationSet( 1, & pAS );
  384.         MultiByteToWideChar( CP_ACP, 0, pAS->GetName(), -1, wstr, 256 );
  385.         swprintf( s, L"Track 1: %s%s", wstr, m_dwCurrentTrack == 1 ? L" (current)" : L"" );
  386.         v_sReport.push_back( String( s ) );
  387.         pAS->Release();
  388.  
  389.         pAC->GetTrackDesc( 1, & td );
  390.         swprintf( s, L"  Weight: %f", td.Weight );
  391.         v_sReport.push_back( String( s ) );
  392.         swprintf( s, L"  Speed: %f", td.Speed );
  393.         v_sReport.push_back( String( s ) );
  394.         swprintf( s, L"  Position: %f", td.Position );
  395.         v_sReport.push_back( String( s ) );
  396.         swprintf( s, L"  Enable: %s", td.Enable ? L"true" : L"false" );
  397.         v_sReport.push_back( String( s ) );
  398.  
  399.         if( m_bUserControl )
  400.         {
  401.             swprintf( s, L"Control: USER" );
  402.             v_sReport.push_back( String( s ) );
  403.         } else
  404.         {
  405.             swprintf( s, L"Control: AUTO" );
  406.             v_sReport.push_back( String( s ) );
  407.         }
  408.  
  409.         pAC->Release();
  410.     }
  411.     catch( ... )
  412.     {
  413.     }
  414. }
  415.  
  416.  
  417.  
  418.  
  419. //-----------------------------------------------------------------------------
  420. // Specifies that this instance of CTiny is controlled by the user.
  421. void CTiny::SetUserControl()
  422. {
  423.     m_bUserControl = true;
  424. }
  425.  
  426.  
  427. //-----------------------------------------------------------------------------
  428. // Specifies that this instance of CTiny is controlled by the application.
  429. void CTiny::SetAutoControl()
  430. {
  431.     if( m_bUserControl )
  432.     {
  433.         m_bUserControl = false;
  434.         SetSeekingState();
  435.     }
  436. }
  437.  
  438.  
  439. //-----------------------------------------------------------------------------
  440. // Name: CTiny::SetSounds()
  441. // Desc: Enables or disables the sound support for this instance of CTiny.
  442. //       In this case, whether we hear the footstep sound or not.
  443. //-----------------------------------------------------------------------------
  444. void CTiny::SetSounds( bool bSounds )
  445. {
  446.     m_bPlaySounds = bSounds;
  447. }
  448.  
  449.  
  450.  
  451.  
  452. //-----------------------------------------------------------------------------
  453. // Name: CTiny::ChooseNewLocation()
  454. // Desc: Determine a new location for this character to move to.  In this case
  455. //       we simply randomly pick a spot on the floor as the new location.
  456. //-----------------------------------------------------------------------------
  457. void CTiny::ChooseNewLocation( D3DXVECTOR3 *pV )
  458. {
  459.     pV->x = (float) ( rand() % 256 ) / 256.f;
  460.     pV->y = 0.f;
  461.     pV->z = (float) ( rand() % 256 ) / 256.f;
  462. }
  463.  
  464.  
  465.  
  466.  
  467. //-----------------------------------------------------------------------------
  468. // Name: CTiny::IsBlockedByCharacter()
  469. // Desc: Goes through the character list nad returns true if this instance is
  470. //       blocked by any other such that it cannot move, or false otherwise.
  471. //-----------------------------------------------------------------------------
  472. bool CTiny::IsBlockedByCharacter( D3DXVECTOR3 * pV )
  473. {
  474.     D3DXVECTOR3 vSub;
  475.  
  476.     // move through each character to see if it blocks this
  477.     vector< CTiny* >::iterator itCur, itEnd = m_pv_pChars->end();
  478.     for( itCur = m_pv_pChars->begin(); itCur != itEnd; ++ itCur )
  479.     {
  480.         CTiny * pChar = * itCur;
  481.         if( pChar == this )      // don't test against ourselves
  482.             continue;
  483.  
  484.         D3DXVECTOR3 vSub;
  485.         D3DXVec3Subtract( & vSub, & pChar->m_vPos, pV );
  486.         float fRadiiSq = pChar->m_fPersonalRadius + m_fPersonalRadius;
  487.         fRadiiSq *= fRadiiSq;
  488.  
  489.         // test distance
  490.         if( D3DXVec3LengthSq( & vSub ) < fRadiiSq )
  491.         {
  492.                 return true;
  493.         }
  494.     }
  495.  
  496.     return false;
  497. }
  498.  
  499.  
  500.  
  501.  
  502. //-----------------------------------------------------------------------------
  503. // Name: CTiny::IsOutOfBounds()
  504. // Desc: Checks this instance against its bounds.  Returns true if it has moved
  505. //       outside the boundaries, or false if not.  In this case, we check if
  506. //       x and z are within the required range (0 to 1).
  507. //-----------------------------------------------------------------------------
  508. bool CTiny::IsOutOfBounds( D3DXVECTOR3 *pV )
  509. {
  510.     if( pV->x < 0.0 || pV->x > 1.0 || pV->z < 0.0 || pV->z > 1.0 )
  511.         return true;
  512.     else
  513.         return false;
  514. }
  515.  
  516.  
  517.  
  518.  
  519. //-----------------------------------------------------------------------------
  520. // Name: CTiny::GetAnimIndex()
  521. // Desc: Returns the index of an animation set within this animation instance's
  522. //       animation controller given an animation set name.
  523. //-----------------------------------------------------------------------------
  524. DWORD CTiny::GetAnimIndex( char sString[] )
  525. {
  526.     HRESULT hr;
  527.     LPD3DXANIMATIONCONTROLLER pAC;
  528.     LPD3DXANIMATIONSET pAS;
  529.     DWORD dwRet = ANIMINDEX_FAIL;
  530.  
  531.     m_pAI->GetAnimController( & pAC );
  532.  
  533.     for( DWORD i = 0; i < pAC->GetNumAnimationSets(); ++ i )
  534.     {
  535.         hr = pAC->GetAnimationSet( i, & pAS );
  536.         if( FAILED( hr ) )
  537.             continue;
  538.  
  539.         if( pAS->GetName() &&
  540.             !strncmp( pAS->GetName(), sString, min( strlen( pAS->GetName() ), strlen( sString ) ) ) )
  541.         {
  542.             dwRet = i;
  543.             pAS->Release();
  544.             break;
  545.         }
  546.  
  547.         pAS->Release();
  548.     }
  549.  
  550.     pAC->Release();
  551.  
  552.     return dwRet;
  553. }
  554.  
  555.  
  556.  
  557.  
  558. //-----------------------------------------------------------------------------
  559. // Name: CTiny::AddCallbackKeysAndCompress()
  560. // Desc: Replaces an animation set in the animation controller with the
  561. //       compressed version and callback keys added to it.
  562. //-----------------------------------------------------------------------------
  563. HRESULT CTiny::AddCallbackKeysAndCompress( LPD3DXANIMATIONCONTROLLER pAC,
  564.                                            LPD3DXKEYFRAMEDANIMATIONSET pAS,
  565.                                            DWORD dwNumCallbackKeys,
  566.                                            D3DXKEY_CALLBACK aKeys[],
  567.                                            DWORD dwCompressionFlags,
  568.                                            FLOAT fCompression )
  569. {
  570.     HRESULT hr;
  571.     LPD3DXCOMPRESSEDANIMATIONSET pASNew = NULL;
  572.     LPD3DXBUFFER pBufCompressed = NULL;
  573.  
  574.     hr = pAS->Compress( dwCompressionFlags, fCompression, NULL, &pBufCompressed );
  575.     if( FAILED( hr ) )
  576.         goto e_Exit;
  577.  
  578.     hr = D3DXCreateCompressedAnimationSet( pAS->GetName(),
  579.                                            pAS->GetSourceTicksPerSecond(),
  580.                                            pAS->GetPlaybackType(),
  581.                                            pBufCompressed,
  582.                                            dwNumCallbackKeys,
  583.                                            aKeys,
  584.                                            &pASNew );
  585.     pBufCompressed->Release();
  586.  
  587.     if( FAILED( hr ) )
  588.         goto e_Exit;
  589.  
  590.     pAC->UnregisterAnimationSet( pAS );
  591.     pAS->Release();
  592.  
  593.     hr = pAC->RegisterAnimationSet( pASNew );
  594.     if( FAILED( hr ) )
  595.         goto e_Exit;
  596.  
  597.     pASNew->Release();
  598.     pASNew = NULL;
  599.  
  600.  
  601. e_Exit:
  602.     
  603.     if( pASNew )
  604.         pASNew->Release();
  605.  
  606.     return hr;
  607. }
  608.  
  609.  
  610.  
  611.  
  612. //-----------------------------------------------------------------------------
  613. // Name: CTiny::SetupCallbacksAndCompression()
  614. // Desc: Add callback keys to the walking and jogging animation sets in the
  615. //       animation controller for playing footstepping sound.  Then compress
  616. //       all animation sets in the animation controller.
  617. //-----------------------------------------------------------------------------
  618. HRESULT CTiny::SetupCallbacksAndCompression()
  619. {
  620.     LPD3DXANIMATIONCONTROLLER pAC;
  621.     LPD3DXKEYFRAMEDANIMATIONSET pASLoiter, pASWalk, pASJog;
  622.  
  623.     m_pAI->GetAnimController( & pAC );
  624.     pAC->GetAnimationSet( m_dwAnimIdxLoiter, (LPD3DXANIMATIONSET *) & pASLoiter );
  625.     pAC->GetAnimationSet( m_dwAnimIdxWalk, (LPD3DXANIMATIONSET *) & pASWalk );
  626.     pAC->GetAnimationSet( m_dwAnimIdxJog, (LPD3DXANIMATIONSET *) & pASJog );
  627.  
  628.     D3DXKEY_CALLBACK aKeysWalk[ 2 ];
  629.     aKeysWalk[ 0 ].Time = 0;
  630.     aKeysWalk[ 0 ].pCallbackData = & m_CallbackData[ 0 ];
  631.     aKeysWalk[ 1 ].Time = float( pASWalk->GetPeriod() / 2.0 * pASWalk->GetSourceTicksPerSecond() );
  632.     aKeysWalk[ 1 ].pCallbackData = & m_CallbackData[ 1 ];
  633.  
  634.     D3DXKEY_CALLBACK aKeysJog[ 8 ];
  635.     for( int i = 0; i < 8; ++ i )
  636.     {
  637.         aKeysJog[ i ].Time = float( pASJog->GetPeriod() / 8 * (double) i * pASWalk->GetSourceTicksPerSecond() );
  638.         aKeysJog[ i ].pCallbackData = & m_CallbackData[ ( i + 1 ) % 2 ];
  639.     }
  640.  
  641.     AddCallbackKeysAndCompress( pAC, pASLoiter, 0, NULL, D3DXCOMPRESS_DEFAULT, .8f );
  642.     AddCallbackKeysAndCompress( pAC, pASWalk, 2, aKeysWalk, D3DXCOMPRESS_DEFAULT, .4f );
  643.     AddCallbackKeysAndCompress( pAC, pASJog, 8, aKeysJog, D3DXCOMPRESS_DEFAULT, .25f );
  644.  
  645.     m_dwAnimIdxLoiter = GetAnimIndex( "Loiter" );
  646.     m_dwAnimIdxWalk = GetAnimIndex( "Walk" );
  647.     m_dwAnimIdxJog = GetAnimIndex( "Jog" );
  648.     if( m_dwAnimIdxLoiter == ANIMINDEX_FAIL ||
  649.         m_dwAnimIdxWalk == ANIMINDEX_FAIL ||
  650.         m_dwAnimIdxJog == ANIMINDEX_FAIL )
  651.         return E_FAIL;
  652.  
  653.     pAC->Release();
  654.  
  655.     return S_OK;
  656. }
  657.  
  658.  
  659.  
  660.  
  661. //-----------------------------------------------------------------------------
  662. // Name: CTiny::SmoothLoiter()
  663. // Desc: If Tiny is loitering, check if we have reached the end of animation.
  664. //       If so, set up a new track to play Loiter animation from the start and
  665. //       smoothly transition to the track, so that Tiny can loiter more.
  666. //-----------------------------------------------------------------------------
  667. void CTiny::SmoothLoiter()
  668. {
  669.     LPD3DXANIMATIONCONTROLLER pAC;
  670.     LPD3DXANIMATIONSET pASTrack, pASLoiter;
  671.     m_pAI->GetAnimController( & pAC );
  672.  
  673.     // check if we're loitering
  674.     pAC->GetTrackAnimationSet( m_dwCurrentTrack, & pASTrack );
  675.     pAC->GetAnimationSet( m_dwAnimIdxLoiter, & pASLoiter );
  676.     if( pASTrack && pASTrack == pASLoiter )
  677.     {
  678.         D3DXTRACK_DESC td;
  679.         pAC->GetTrackDesc( m_dwCurrentTrack, & td );
  680.         if( td.Position > pASTrack->GetPeriod() - IDLE_TRANSITION_TIME )  // come within the change delta of the end
  681.             SetIdleKey( true );
  682.     }
  683.  
  684.     SAFE_RELEASE( pASTrack );
  685.     SAFE_RELEASE( pASLoiter );
  686.     SAFE_RELEASE( pAC );
  687. }
  688.  
  689.  
  690.  
  691.  
  692. //-----------------------------------------------------------------------------
  693. // Name: CTiny::SetNewTarget()
  694. // Desc: This only applies when Tiny is under automatic movement control.  If
  695. //       this instnace of Tiny is blocked by either the edge of another
  696. //       instance of Tiny, find a new location to walk to.
  697. //-----------------------------------------------------------------------------
  698. void CTiny::SetNewTarget()
  699. {
  700.     // get new position
  701.     bool bBlocked = true;
  702.     DWORD dwAttempts;
  703.     for( dwAttempts = 0; dwAttempts < 1000 && bBlocked; ++ dwAttempts )
  704.     {
  705.         ChooseNewLocation( & m_vPosTarget );
  706.         bBlocked = IsBlockedByCharacter( & m_vPosTarget );
  707.     }
  708.  
  709.     ComputeFacingTarget();
  710. }
  711.  
  712.  
  713.  
  714.  
  715. //-----------------------------------------------------------------------------
  716. // Name: CTiny::GetSpeedScale()
  717. // Desc: Returns the speed of the current track.
  718. //-----------------------------------------------------------------------------
  719. double CTiny::GetSpeedScale()
  720. {
  721.     LPD3DXANIMATIONCONTROLLER pAC;
  722.     D3DXTRACK_DESC td;
  723.  
  724.     if( m_bIdle )
  725.         return 1.0;
  726.     else
  727.     {
  728.         m_pAI->GetAnimController( & pAC );
  729.         pAC->GetTrackDesc( m_dwCurrentTrack, & td );
  730.         pAC->Release();
  731.  
  732.         return td.Speed;
  733.     }
  734. }
  735.  
  736.  
  737.  
  738.  
  739. //-----------------------------------------------------------------------------
  740. // Name: CTiny::AnimateUserControl()
  741. // Desc: Reads user input and update Tiny's state and animation accordingly.
  742. //-----------------------------------------------------------------------------
  743. void CTiny::AnimateUserControl( double dTimeDelta )
  744. {
  745.     // use keyboard controls to make Tiny move
  746.  
  747.     bool bCanMove;
  748.  
  749.     if( GetKeyState( 'V' ) < 0 )
  750.     {
  751.         m_bUserControl = false;
  752.         SetSeekingState();
  753.         return;
  754.     }
  755.  
  756.     if( GetKeyState( 'W' ) < 0 )
  757.     {
  758.         bCanMove = true;
  759.  
  760.         if( GetAsyncKeyState( VK_SHIFT ) < 0 )
  761.         {
  762.             if( m_fSpeed == m_fSpeedWalk )
  763.             {
  764.                 m_fSpeed = m_fSpeedJog;
  765.                 m_bIdle = true;  // Set idle to true so that we can reset the movement animation below
  766.             }
  767.         }
  768.         else
  769.         {
  770.             if( m_fSpeed == m_fSpeedJog )
  771.             {
  772.                 m_fSpeed = m_fSpeedWalk;
  773.                 m_bIdle = true;  // Set idle to true so that we can reset the movement animation below
  774.             }
  775.         }
  776.  
  777.         D3DXVECTOR3 vMovePos;
  778.         GetFacing( &vMovePos );
  779.         D3DXVec3Scale( &vMovePos, &vMovePos, float( m_fSpeed * GetSpeedScale() * dTimeDelta ) );
  780.         D3DXVec3Add( & vMovePos, & vMovePos, & m_vPos );
  781.  
  782.         // is our step ahead going to take us out of bounds?
  783.         if( IsOutOfBounds( & vMovePos ) )
  784.             bCanMove = false;
  785.  
  786.         // are we stepping on someone else?
  787.         if( IsBlockedByCharacter( & vMovePos ) )
  788.             bCanMove = false;
  789.  
  790.         if( bCanMove )
  791.             m_vPos = vMovePos;
  792.     }
  793.     else
  794.         bCanMove = false;
  795.  
  796.  
  797.     if( m_bIdle && bCanMove )
  798.     {
  799.         SetMoveKey();
  800.         m_bIdle = false;
  801.     }
  802.  
  803.     if( ! m_bIdle && ! bCanMove )
  804.     {
  805.         SetIdleKey( true );
  806.         m_bIdle = true;
  807.     }
  808.  
  809.     // turn
  810.     if( GetKeyState( 'A' ) < 0 )
  811.         m_fFacing = float( m_fFacing + m_fSpeedTurn * dTimeDelta );
  812.  
  813.     if( GetKeyState( 'D' ) < 0 )
  814.         m_fFacing = float( m_fFacing - m_fSpeedTurn * dTimeDelta );
  815. }
  816.  
  817.  
  818.  
  819.  
  820. //-----------------------------------------------------------------------------
  821. // Name: CTiny::AnimateIdle()
  822. // Desc: Checks if Tiny has been idle for long enough.  If so, initialize Tiny
  823. //       to move again to a new location.
  824. //-----------------------------------------------------------------------------
  825. void CTiny::AnimateIdle( double dTimeDelta )
  826. {
  827.     // count down the idle counters
  828.     if( m_dTimeIdling > 0.0 )
  829.         m_dTimeIdling -= dTimeDelta;
  830.  
  831.     // if idle time runs out, pick a new location
  832.     if( m_dTimeIdling <= 0.0 )
  833.         SetSeekingState();
  834. }
  835.  
  836.  
  837.  
  838.  
  839. //-----------------------------------------------------------------------------
  840. // Name: CTiny::AnimateMoving()
  841. // Desc: Here we try to figure out if we're moving and can keep moving, 
  842. //       or if we're waiting / blocked and must keep waiting / blocked,
  843. //       or if we have reached our destination.
  844. //-----------------------------------------------------------------------------
  845. void CTiny::AnimateMoving( double dTimeDelta )
  846. {
  847.     // move, then turn
  848.     D3DXVECTOR3 vMovePos;
  849.     D3DXVECTOR3 vSub;
  850.     float fDist;
  851.  
  852.     if( m_bWaiting )
  853.     {
  854.         if( m_dTimeWaiting > 0.0 )
  855.             m_dTimeWaiting -= dTimeDelta;
  856.  
  857.         if( m_dTimeWaiting <= 0.0 )
  858.         {
  859.             SetNewTarget();
  860.             m_dTimeWaiting = 4.0;
  861.         }
  862.     }
  863.  
  864.     // get distance from target
  865.     D3DXVec3Subtract( & vSub, & m_vPos, & m_vPosTarget );
  866.     fDist = D3DXVec3LengthSq( & vSub );
  867.     double dSpeedScale = GetSpeedScale();
  868.  
  869.     if( m_dTimeBlocked > 0.0 )                  // if we're supposed to wait, then turn only
  870.     {
  871.         m_dTimeBlocked -= dTimeDelta;
  872.     }
  873.     // TODO: help next line
  874.     else if( m_fSpeed * dSpeedScale * dTimeDelta * m_fSpeed * dSpeedScale * dTimeDelta >= fDist )
  875.     {
  876.         // we're within reach; set the exact point
  877.         m_vPos = m_vPosTarget;
  878.         SetIdleState();
  879.     }
  880.     else
  881.     {
  882.         // moving forward
  883.         GetFacing( &vMovePos );
  884.         D3DXVec3Scale( &vMovePos, &vMovePos, float( m_fSpeed * dSpeedScale * dTimeDelta ) );
  885.         D3DXVec3Add( & vMovePos, & vMovePos, & m_vPos );
  886.  
  887.         bool bCanMove = true;
  888.         bool bOrbit = false;
  889.  
  890.         // is our step ahead going to take us out of bounds?
  891.         if( IsOutOfBounds( & vMovePos ) )
  892.             bCanMove = false;
  893.  
  894.         // are we stepping on someone else?
  895.         if( IsBlockedByCharacter( & vMovePos ) )
  896.             bCanMove = false;
  897.  
  898.         // are we orbiting our target?
  899.         if( ( m_fFacing != m_fFacingTarget ) && 
  900.             ( fDist <= ( ( m_fSpeed * m_fSpeed ) / ( m_fSpeedTurn * m_fSpeedTurn ) ) ) )
  901.         {
  902.             bOrbit = true;
  903.             bCanMove = false;
  904.         }
  905.  
  906.         // set keys if we have to
  907.         if( bCanMove && m_bWaiting )
  908.         {
  909.             SetMoveKey();
  910.             m_bWaiting = false;
  911.         }
  912.  
  913.         if( ! bCanMove && ! m_bWaiting )
  914.         {
  915.             SetIdleKey( false );
  916.             m_bWaiting = true;
  917.             if( ! bOrbit )
  918.                 m_dTimeBlocked = 1.0;
  919.         }
  920.  
  921.         if( bCanMove )
  922.             m_vPos = vMovePos;
  923.     }
  924.  
  925.     // turning
  926.     if( m_fFacingTarget != m_fFacing )
  927.     {
  928.         float fFacing = m_fFacingTarget;
  929.         if( m_fFacingTarget > m_fFacing )
  930.             fFacing -= 2 * D3DX_PI;
  931.  
  932.         float fDiff = m_fFacing - fFacing;
  933.         if( fDiff < D3DX_PI )       // cw turn
  934.         {
  935.             // if we're overturning
  936.             if( m_fFacing - m_fSpeedTurn * dTimeDelta <= fFacing )
  937.                 m_fFacing = m_fFacingTarget;
  938.             else
  939.                 m_fFacing = float( m_fFacing - m_fSpeedTurn * dTimeDelta );
  940.         }
  941.         else                        // ccw turn
  942.         {
  943.             // if we're overturning
  944.             if( m_fFacing + m_fSpeedTurn * dTimeDelta - 2 * D3DX_PI >= fFacing )
  945.                 m_fFacing = m_fFacingTarget;
  946.             else
  947.                 m_fFacing = float( m_fFacing + m_fSpeedTurn * dTimeDelta );
  948.         }
  949.  
  950.         ComputeFacingTarget();
  951.     }
  952. }
  953.  
  954.  
  955.  
  956.  
  957. //-----------------------------------------------------------------------------
  958. // Name: CTiny::ComputeFacingTarget()
  959. // Desc: Computes the direction in forms of both an angle and a vector that
  960. //       Tiny is facing.
  961. //-----------------------------------------------------------------------------
  962. void CTiny::ComputeFacingTarget()
  963. {
  964.     D3DXVECTOR3 vDiff;
  965.     D3DXVec3Subtract( & vDiff, & m_vPosTarget, & m_vPos );
  966.     D3DXVec3Normalize( & vDiff, & vDiff );
  967.  
  968.     if( vDiff.z == 0.f )
  969.     {
  970.         if( vDiff.x > 0.f )
  971.             m_fFacingTarget = 0.0f;
  972.         else
  973.             m_fFacingTarget = D3DX_PI;
  974.     }
  975.     else if( vDiff.z > 0.f )
  976.         m_fFacingTarget = acosf( vDiff.x );
  977.     else
  978.         m_fFacingTarget = acosf( - vDiff.x ) + D3DX_PI;
  979. }
  980.  
  981.  
  982.  
  983.  
  984. //-----------------------------------------------------------------------------
  985. // Name: CTiny::SetIdleState()
  986. // Desc: This only applies when Tiny is not controlled by the user.  Called
  987. //       when Tiny has just reached a destination.  We let Tiny remain idle
  988. //       for a period of time before a new action is taken.
  989. //-----------------------------------------------------------------------------
  990. void CTiny::SetIdleState()
  991. {
  992.     m_bIdle = true;
  993.     m_dTimeIdling = 4.0;
  994.  
  995.     SetIdleKey( false );
  996. }
  997.  
  998.  
  999.  
  1000.  
  1001. //-----------------------------------------------------------------------------
  1002. // Name: CTiny::SetSeekingState()
  1003. // Desc: Used when the computer controls Tiny.  Find a new location to move
  1004. //       Tiny to, then set the animation controller's tracks to reflect the
  1005. //       change of action.
  1006. //-----------------------------------------------------------------------------
  1007. void CTiny::SetSeekingState()
  1008. {
  1009.     m_bIdle = false;
  1010.     m_bWaiting = false;
  1011.  
  1012.     SetNewTarget();
  1013.  
  1014.     if( rand() % 5 )
  1015.         m_fSpeed = m_fSpeedWalk;
  1016.     else
  1017.         m_fSpeed = m_fSpeedJog;
  1018.  
  1019.     SetMoveKey();
  1020. }
  1021.  
  1022.  
  1023.  
  1024.  
  1025. //-----------------------------------------------------------------------------
  1026. // Name: CTiny::SetMoveKey()
  1027. // Desc: Initialize a new track in the animation controller for the movement
  1028. //       animation (run or walk), and set up the smooth transition from the idle
  1029. //       animation (current track) to it (new track).
  1030. //-----------------------------------------------------------------------------
  1031. void CTiny::SetMoveKey()
  1032. {
  1033.     DWORD dwNewTrack = ( m_dwCurrentTrack == 0 ? 1 : 0 );
  1034.     LPD3DXANIMATIONCONTROLLER pAC;
  1035.     LPD3DXANIMATIONSET pAS;
  1036.     m_pAI->GetAnimController( & pAC );
  1037.  
  1038.     if( m_fSpeed == m_fSpeedWalk )
  1039.         pAC->GetAnimationSet( m_dwAnimIdxWalk, & pAS );
  1040.     else
  1041.         pAC->GetAnimationSet( m_dwAnimIdxJog, & pAS );
  1042.  
  1043.     pAC->SetTrackAnimationSet( dwNewTrack, pAS );
  1044.     pAS->Release();
  1045.  
  1046.     pAC->UnkeyAllTrackEvents( m_dwCurrentTrack );
  1047.     pAC->UnkeyAllTrackEvents( dwNewTrack );
  1048.  
  1049.     pAC->KeyTrackEnable( m_dwCurrentTrack, FALSE, m_dTimeCurrent + MOVE_TRANSITION_TIME );
  1050.     pAC->KeyTrackSpeed( m_dwCurrentTrack, 0.0f, m_dTimeCurrent, MOVE_TRANSITION_TIME, D3DXTRANSITION_LINEAR );
  1051.     pAC->KeyTrackWeight( m_dwCurrentTrack, 0.0f, m_dTimeCurrent, MOVE_TRANSITION_TIME, D3DXTRANSITION_LINEAR );
  1052.     pAC->SetTrackEnable( dwNewTrack, TRUE );
  1053.     pAC->KeyTrackSpeed( dwNewTrack, 1.0f, m_dTimeCurrent, MOVE_TRANSITION_TIME, D3DXTRANSITION_LINEAR );
  1054.     pAC->KeyTrackWeight( dwNewTrack, 1.0f, m_dTimeCurrent, MOVE_TRANSITION_TIME, D3DXTRANSITION_LINEAR );
  1055.  
  1056.     m_dwCurrentTrack = dwNewTrack;
  1057.  
  1058.     pAC->Release();
  1059. }
  1060.  
  1061.  
  1062.  
  1063.  
  1064. //-----------------------------------------------------------------------------
  1065. // Name: CTiny::SetIdleKey()
  1066. // Desc: Initialize a new track in the animation controller for the idle
  1067. //       (loiter ) animation, and set up the smooth transition from the
  1068. //       movement animation (current track) to it (new track).
  1069. //
  1070. //       bResetPosition controls whether we start the Loiter animation from
  1071. //       its beginning or current position.
  1072. //-----------------------------------------------------------------------------
  1073. void CTiny::SetIdleKey( bool bResetPosition )
  1074. {
  1075.     DWORD dwNewTrack = ( m_dwCurrentTrack == 0 ? 1 : 0 );
  1076.     LPD3DXANIMATIONCONTROLLER pAC;
  1077.     LPD3DXANIMATIONSET pAS;
  1078.     m_pAI->GetAnimController( & pAC );
  1079.  
  1080.     pAC->GetAnimationSet( m_dwAnimIdxLoiter, & pAS );
  1081.     pAC->SetTrackAnimationSet( dwNewTrack, pAS );
  1082.     pAS->Release();
  1083.  
  1084.     pAC->UnkeyAllTrackEvents( m_dwCurrentTrack );
  1085.     pAC->UnkeyAllTrackEvents( dwNewTrack );
  1086.  
  1087.     pAC->KeyTrackEnable( m_dwCurrentTrack, FALSE, m_dTimeCurrent + IDLE_TRANSITION_TIME );
  1088.     pAC->KeyTrackSpeed( m_dwCurrentTrack, 0.0f, m_dTimeCurrent, IDLE_TRANSITION_TIME, D3DXTRANSITION_LINEAR );
  1089.     pAC->KeyTrackWeight( m_dwCurrentTrack, 0.0f, m_dTimeCurrent, IDLE_TRANSITION_TIME, D3DXTRANSITION_LINEAR );
  1090.     pAC->SetTrackEnable( dwNewTrack, TRUE );
  1091.     pAC->KeyTrackSpeed( dwNewTrack, 1.0f, m_dTimeCurrent, IDLE_TRANSITION_TIME, D3DXTRANSITION_LINEAR );
  1092.     pAC->KeyTrackWeight( dwNewTrack, 1.0f, m_dTimeCurrent, IDLE_TRANSITION_TIME, D3DXTRANSITION_LINEAR );
  1093.     if( bResetPosition )
  1094.         pAC->SetTrackPosition( dwNewTrack, 0.0 );
  1095.  
  1096.     m_dwCurrentTrack = dwNewTrack;
  1097.  
  1098.     pAC->Release();
  1099. }
  1100.  
  1101.  
  1102.  
  1103.  
  1104. //-----------------------------------------------------------------------------
  1105. // Name: CTiny::RestoreDeviceObjects()
  1106. // Desc: Reinitialize necessary objects
  1107. //-----------------------------------------------------------------------------
  1108. HRESULT CTiny::RestoreDeviceObjects( LPDIRECT3DDEVICE9 pd3dDevice )
  1109. {
  1110.     // Compress the animation sets in the new animation controller
  1111.     SetupCallbacksAndCompression();
  1112.  
  1113.     LPD3DXANIMATIONCONTROLLER pAC;
  1114.     m_pAI->GetAnimController( & pAC );
  1115.     pAC->ResetTime();
  1116.     pAC->AdvanceTime( m_dTimeCurrent, NULL );
  1117.  
  1118.     // Initialize current track
  1119.     if( m_szASName[0] != '\0' )
  1120.     {
  1121.         DWORD dwActiveSet = GetAnimIndex( m_szASName );
  1122.         LPD3DXANIMATIONSET pAS = NULL;
  1123.         pAC->GetAnimationSet( dwActiveSet, &pAS );
  1124.         pAC->SetTrackAnimationSet( m_dwCurrentTrack, pAS );
  1125.         SAFE_RELEASE( pAS );
  1126.     }
  1127.  
  1128.     pAC->SetTrackEnable( m_dwCurrentTrack, TRUE );
  1129.     pAC->SetTrackWeight( m_dwCurrentTrack, 1.0f );
  1130.     pAC->SetTrackSpeed( m_dwCurrentTrack, 1.0f );
  1131.  
  1132.     SAFE_RELEASE( pAC );
  1133.  
  1134.     // Call animate to initialize the tracks.
  1135.     Animate( 0.0 );
  1136.  
  1137.     return S_OK;
  1138. }
  1139.  
  1140.  
  1141.  
  1142.  
  1143. //-----------------------------------------------------------------------------
  1144. // Name: CTiny::RestoreDeviceObjects()
  1145. // Desc: Free D3D objects so that the device can be reset.
  1146. //-----------------------------------------------------------------------------
  1147. HRESULT CTiny::InvalidateDeviceObjects()
  1148. {
  1149.     // Save the current track's animation set name
  1150.     // so we can reset it again in RestoreDeviceObjects later.
  1151.     LPD3DXANIMATIONCONTROLLER pAC = NULL;
  1152.     m_pAI->GetAnimController( & pAC );
  1153.     if( pAC )
  1154.     {
  1155.         LPD3DXANIMATIONSET pAS = NULL;
  1156.         pAC->GetTrackAnimationSet( m_dwCurrentTrack, &pAS );
  1157.         if( pAS )
  1158.         {
  1159.             if( pAS->GetName() )
  1160.                 strcpy( m_szASName, pAS->GetName() );
  1161.             SAFE_RELEASE( pAS );
  1162.         }
  1163.         SAFE_RELEASE( pAC );
  1164.     }
  1165.  
  1166.     return S_OK;
  1167. }
  1168.